/*
 * This is GPL v2 licensed code. See the file LICENSE in the
 * source distribution, or www.gnu.org/copyleft/gpl.html, for
 * more information.
 *
 * Copyright (C) by Håkan Lindqvist 2006, 2007
 */

package PolicyAlgebra.Type;

/** 
 * This class represents an item that simply is named (ie
 * given a textual identifier / name).
 */
public abstract class NamedAtom implements Comparable {

	private String name;

	/** 
	 * Atoms of same (sub)class may * may still be of different types;
	 * For example, files and directories
	 * are both objects, but not the same type.
	 */
	private Type type;


	/** 
	 * Constructor.
	 * 
	 * @param name The name of this named atom.
	 */
	public NamedAtom(String name) {
		this(name, null);
	}


	/** 
	 * Constructor.
	 * 
	 * @param name The name of this named atom.
	 * @param type A type for this named atom.
	 */
	public NamedAtom(String name, Type type) {
		this.name = name;
		this.type = type;
	}


	/** 
	 * Access method for the name member. 
	 * 
	 * @return The name of this atom.
	 */
	public String getName() {
		return name;
	}


	/** 
	 * Access method for the type member. 
	 * 
	 * @return The type of this atom, possibly null (no type).
	 */
	public Type getType() {
		return type;
	}

	/** 
	 * Compares an instance of a NamedAtom, or sibling, to aother object. 
	 * 
	 * @param other The other object to compare this instance, or sibling, of
	 *        NamedAtom with.
	 * @return 0 if they are equal, -1 if not. -1 is for instance returned if
	 *         other is a sibling of NamedAtom but not of same type as this object.
	 * @throws ClassCastException If the parameter is not a sibling of NamedAtom.
	 */
	public int compareTo(Object other) throws ClassCastException {
		if (! (other instanceof NamedAtom)) {
			throw new ClassCastException("Cannot convert a " + other.getClass()
					+ " to class NamedAtom");
		}

		NamedAtom n = (NamedAtom) other;

		/* They are the exact same type of class. */
		if (this.getClass() == other.getClass()) {
			return this.name.compareTo(n.name);
		} else {
			/* The other object also inherits NamedAtom, but is not of the same class.
			 * Return something that is somewhat appropriate. */
			return -1;
		}
	}


	/** 
	 * Checks if another object is equal to this atom, uses compareTo.
	 * 
	 * @param other The object to check against.
	 * @return True if they are equal, else false.
	 */
	public boolean equals(Object other) {
		return this.compareTo(other) == 0;
	}


	/** 
	 * Return a hashcode for this atom using the name itself
	 * and running it through the 'djb2' algoithm (see:
	 * www.cse.yorku.ca/~oz/hash.html).
	 * 
	 * @return The hashcode for this set.
	 */
	public int hashCode() {
		int hash = 5381;
		char[] a = name.toCharArray();
		int i = 0;

		for (; i<a.length; i++) {
			hash = ((hash << 5) + hash) + a[i]; /* hash * 33 + c */
		}

		return hash;
	}


	/** 
	 *  Custom string transformation method.
	 * 
	 * @return The string representation of this atom.
	 */
	public String toString() {
		return name + ":<" + type + ">";
	}
}
